Flutter 常用布局-单元素布局

单元素布局,指的是一个布局方式中只支持一个子控件,不支持多控件配置。常用的布局方式有Container、Padding、Align、Center等。(这里只说明基本控件,还有其他常用控件,比如Card,也属于单元素布局控件)

Container

Container是一个相对复杂的布局方式,按照文档描述来说,支持绘制、定位、以及调整大小。A convenience widget that combines common painting, positioning, and sizing widgets.

Container属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Container({
Key key,
this.alignment, // 对齐方式
this.padding, // decoration内部的空白区域,子控件在padding中
Color color, // container颜色,注意如果同时存在color与decoration,会出现错误
Decoration decoration, // 背景装饰,可以进行较为复杂的设计效果
this.foregroundDecoration, // 前景装饰
double width, // 控件宽度
double height, // 控件高度
BoxConstraints constraints, // 子控件约束条件
this.margin, // decoration外的空白区域
this.transform, // 变换矩阵
this.child, // 子控件
})

上面注释中简单说明了每个属性的作用,具体布局情况见下图:

绘制过程

按照以下属性顺序绘制。

  • transform

先进行矩阵坐标变换,在转换后的矩阵上进行绘制,例如:

1
2
3
4
5
6
7
8
9
body: new Container(
width: 50,
height: 100,
decoration: new BoxDecoration(
border: new Border.all(width: 2.0, color: Colors.red),
color: Colors.green,
),
transform: Matrix4.rotationZ(0.3)..translate(50.0),
),

效果如下:

  • decoration

背景装饰,支持color(背景颜色)、image(图片)、border(边框)、borderRadius(圆角边框)、boxShadow(阴影)、gradient(渐变)、backgroundBlendMode(混合模式)、shape(枚举,只支持矩形和圆形)配置。如:

1
2
3
4
5
6
7
8
9
decoration: new BoxDecoration(
border: new Border.all(width: 2.0, color: Colors.red),
color: Colors.grey,
borderRadius: new BorderRadius.all(new Radius.circular(20.0)),
image: new DecorationImage(
image: new NetworkImage('http://h.hiphotos.baidu.com/zhidao/wh%3D450%2C600/sign=0d023672312ac65c67506e77cec29e27/9f2f070828381f30dea167bbad014c086e06f06c.jpg'),
centerSlice: new Rect.fromLTRB(270.0, 180.0, 1360.0, 730.0),
),
)
  • child 子控件

只支持唯一的子控件,可以没有子控件。

  • foregroundDecoration

前景装饰,由于最后绘制,可能会遮挡子控件。

布局策略

策略顺序,看官方文档

Container tries, in order: to honor alignment, to size itself to the child, to honor the width, height, and constraints, to expand to fit the parent, to be as small as possible.

也就是说顺序如下:

  • alignment 首先进行对齐操作
  • 根据子控件调整自身大小
  • 使用width、height以及constraints参数设置控件大小
  • 尽可能填充父控件的空间
  • 尽可能减少自身大小

也就是说控件本身的大小会进行如下判断:

  • alignment 属性是否为null,如果非空,那么整个控件大小会尽量充满父控件;如果父控件设置了unbounded,会尽可能的缩小控件。
  • 如果上一步没有确定控件大小,这里会将其设置为子控件大小
  • 根据width、height以及constraints来设置控件大小,如果没有,忽略。经过测试,如果同时配置了width、height和constraints,优先使用constraints里面的参数,看源码处理也是如此。
  • 如果上面都没有确定空间大小,则根据父控件配置项,默认充满父控件,如果父控件设置了unbounded,会尽可能的缩小控件。

上面的判断过程基本上就是整个控件大小的确定过程。然后在这个基础上增加Padding以及Margin的绘制。

Padding

Padding实际上很容易理解,看它的构造方法:

1
2
3
4
5
const Padding({
Key key,
@required this.padding,
Widget child,
})

这个控件是基础控件,而不像Container是一个组合控件,它提供了一个内距为padding的子控件布局。如果子控件不存在,则会产生一个宽为left+right,高为top+bottom的区域。

Flutter中不存在Align控件,如果要实现Align效果,也需要通过Padding来完成。

Align

Align的布局也比较简单,看构造方法:

1
2
3
4
5
6
7
const Align({
Key key,
this.alignment = Alignment.center,
this.widthFactor,
this.heightFactor,
Widget child
})
  • alignment设置对齐方式,支持多种对齐方式,包括左上、左中、左下、中上、居中、中下、右上、右中、右下等,同时也支持自定义对齐,以坐标方式表示。
  • widthFactor、heightFactor表示宽度、高度的缩放比例,不能为负数。最后控件的大小就是这个缩放比例*子控件的大小。

Center

Center继承自Align,不过是将alignment设置为Alignment.center,其它参数与Align完全一致,使用方法也完全一致。

总结

可以说,Container是单元素布局的集大成者,其它所有单元素控件的能力都可以支持。如果想要做好界面展示效果,首先就需要对Container进行深入了解,玩出花来。